package cn.ruleengine.web.config;

import cn.ruleengine.core.DecisionTableEngine;
import cn.ruleengine.core.GeneralRuleEngine;
import cn.ruleengine.core.RuleEngineConfiguration;
import cn.ruleengine.core.RuleSetEngine;
import cn.ruleengine.core.cache.DefaultFunctionCache;
import cn.ruleengine.core.cache.RedisUtil;
import cn.ruleengine.web.service.VariableResolveService;
import cn.ruleengine.web.service.decisiontable.DecisionTablePublishService;
import cn.ruleengine.web.service.generalrule.GeneralRulePublishService;
import cn.ruleengine.web.service.ruleset.RuleEngineRuleSetService;
import cn.ruleengine.web.service.ruleset.RuleSetPublishService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.concurrent.BasicThreadFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;


@Slf4j
@Component
public class EngineConfig {

    @Resource
    private VariableResolveService variableResolveService;

    @Resource
    private GeneralRulePublishService rulePublishService;

    @Resource
    private DecisionTablePublishService decisionTablePublishService;

    @Resource
    private RuleSetPublishService ruleSetPublishService;

    @Resource
    private RuleEngineRuleSetService ruleEngineRuleSetService;

    private final ScheduledExecutorService scheduledExecutorService = new ScheduledThreadPoolExecutor(1,
            new BasicThreadFactory.Builder().namingPattern("engine-config-schedule-pool-%d").daemon(true).build());

    /**
     * 规则引擎配置
     *
     * @return RuleEngineConfiguration
     */
    @Bean(destroyMethod = "close")
    public RuleEngineConfiguration ruleEngineConfiguration(RedisUtil redisUtil) {
        RuleEngineConfiguration configuration = new RuleEngineConfiguration();
        scheduledExecutorService.scheduleAtFixedRate(() -> refresh(configuration), 3, 60 * 5, TimeUnit.SECONDS);
        return configuration;
    }

    public void refresh(RuleEngineConfiguration configuration) {
        configuration.getEngineVariable().addMultipleVariable(this.variableResolveService.getAllVariable());
        configuration.setFunctionCache(new DefaultFunctionCache(1000));
        configuration.getRuleEngineRuleSetPublishCache().addMultiple(ruleSetPublishService.getAllPublishRuleSetMap());
        configuration.getRuleEngineRuleSetCache().addMultiple(ruleEngineRuleSetService.getAllRuleSetMap());
        log.info("engineConfig refresh end.");
    }

    /**
     * 规则引擎
     *
     * @return engine
     */
    @Primary
    @Bean(destroyMethod = "close")
    public GeneralRuleEngine generalRuleEngine(RuleEngineConfiguration ruleEngineConfiguration) {
        log.info("开始初始化普通规则引擎");
        GeneralRuleEngine ruleEngine = new GeneralRuleEngine(ruleEngineConfiguration);
        ruleEngine.addMultiple(this.rulePublishService.getAllPublishGeneralRule());
        log.info("普通规则引擎初始化完毕");
        return ruleEngine;
    }

    /**
     * 决策表引擎
     *
     * @return engine
     */
    @Bean(destroyMethod = "close")
    public DecisionTableEngine decisionTableEngine(RuleEngineConfiguration ruleEngineConfiguration) {
        log.info("开始初始化决策表引擎");
        DecisionTableEngine ruleEngine = new DecisionTableEngine(ruleEngineConfiguration);
        ruleEngine.addMultiple(this.decisionTablePublishService.getAllPublishDecisionTable());
        log.info("决策表引擎初始化完毕");
        return ruleEngine;
    }

    /**
     * 规则集引擎
     *
     * @return engine
     */
    @Bean(destroyMethod = "close")
    public RuleSetEngine ruleSetEngine(RuleEngineConfiguration ruleEngineConfiguration) {
        log.info("开始初始化规则集引擎");
        RuleSetEngine ruleSetEngine = new RuleSetEngine(ruleEngineConfiguration);
        ruleSetEngine.addMultiple(this.ruleSetPublishService.getAllPublishRuleSet());
        log.info("规则集引擎初始化完毕");
        return ruleSetEngine;
    }

}
